<!DOCTYPE html>
<html>

<head>
<title> WebRTC stats</title>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/webrtc-adapter/6.4.0/adapter.min.js" ></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js" ></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.blockUI/2.70/jquery.blockUI.min.js" ></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<style>
  #statsdiv {
      border: 1px solid #10da35

  }
</style>
</head>

<body>
    <h2> WebRTC stats</h2>
    <video id="v1" width="320" height="240" controls autoplay muted></video>
    <video id="v2" width="320" height="240" controls autoplay></video><br>
    <table>
      <tr>
        <td><button onclick="start()">Start!</button></td>
        <td><div id="statediv"></div></td>
    </tr></table>
    <label><input type="checkbox" onclick="mute()">mute</label>
    <div id="div"></div><br><div id="statsdiv"></div>

    <script>
      
        var pc1 = new RTCPeerConnection();
        var pc2 = new RTCPeerConnection();
      
        var add = (pc, can) => can && pc.addIceCandidate(can).catch(log);
        pc1.onicecandidate = e => add(pc2, e.candidate);
        pc2.onicecandidate = e => add(pc1, e.candidate);
      
        pc2.oniceconnectionstatechange = () => update(statediv, pc2.iceConnectionState);
        pc2.onaddstream = e => v2.srcObject = e.stream;
      
        var mute = () => v1.srcObject.getTracks().forEach(t => t.enabled = !t.enabled);
        var start = () => navigator.mediaDevices.getUserMedia({
            video: true,
            audio: true
          })
          .then(stream => (pc1.addStream(v1.srcObject = stream), pc1.createOffer()))
          .then(offer => pc1.setLocalDescription(offer))
          .then(() => pc2.setRemoteDescription(pc1.localDescription))
          .then(() => pc2.createAnswer())
          .then(answer => pc2.setLocalDescription(answer))
          .then(() => pc1.setRemoteDescription(pc2.localDescription))
          .then(() => repeat(10, () => Promise.all([pc1.getStats(), pc2.getStats()])
            .then(([s1, s2]) => {
              var s = "";
              s1.forEach(stat => {
                if (stat.type == "outbound-rtp" && !stat.isRemote) {
                  s += "<h4>Sender side</h4>" + dumpStats(stat);
                }
                //if(stat.type == "codec") {
                //  s += "<p> codec clockRate=" + stat.clockRate + "</p>"
                //}
              });
              s2.forEach(stat => {
                if (stat.type == "inbound-rtp" && !stat.isRemote) {
                  s += "<h4>Receiver side</h4>" + dumpStats(stat);
                }
                //if(stat.type == "codec") {
                //  s += "<p> code clockRate=" + stat.clockRate + "</p>"
                //}
              });
              update(statsdiv, "<small>" + s + "</small>");
            })))
          .catch(e => log(e));
      
        function dumpStats(o) {
          var s = "Timestamp: " + new Date(o.timestamp).toTimeString() + " Type: " + o.type + "<br>";
          if (o.ssrc !== undefined) s += "SSRC: " + o.ssrc + " ";
          if (o.packetsReceived !== undefined) {
            s += "Recvd: " + o.packetsReceived + " packets";
            if (o.bytesReceived !== undefined) {
              s += " (" + (o.bytesReceived / 1024000).toFixed(2) + " MB)";
            }
            if (o.packetsLost !== undefined) s += " Lost: " + o.packetsLost;
          } else if (o.packetsSent !== undefined) {
            s += "Sent: " + o.packetsSent + " packets";
            if (o.bytesSent !== undefined) s += " (" + (o.bytesSent / 1024000).toFixed(2) + " MB)";
          } else {
            s += "<br><br>";
          }
          s += "<br>";
          if (o.bitrateMean !== undefined) {
            s += " Avg. bitrate: " + (o.bitrateMean / 1000000).toFixed(2) + " Mbps";
            if (o.bitrateStdDev !== undefined) {
              s += " (" + (o.bitrateStdDev / 1000000).toFixed(2) + " StdDev)";
            }
            if (o.discardedPackets !== undefined) {
              s += " Discarded packts: " + o.discardedPackets;
            }
          }
          s += "<br>";
          if (o.framerateMean !== undefined) {
            s += " Avg. framerate: " + (o.framerateMean).toFixed(2) + " fps";
            if (o.framerateStdDev !== undefined) {
              s += " (" + o.framerateStdDev.toFixed(2) + " StdDev)";
            }
          }
      
          if (o.droppedFrames !== undefined) s += " Dropped frames: " + o.droppedFrames;
          if (o.jitter !== undefined) s += " Jitter: " + o.jitter;
          return s;
        }
      
        var wait = ms => new Promise(r => setTimeout(r, ms));
        var repeat = (ms, func) => new Promise(r => (setInterval(func, ms), wait(ms).then(r)));
        var log = msg => div.innerHTML = div.innerHTML + msg + "<br>";
        var update = (div, msg) => div.innerHTML = msg;

      </script>

  </body>
</html>